#include "ExampleScene.h"

#include <graphics/utils.h>
#include <graphics/stlloader.h>
#include <assert.h>
#include <render/renderer.h>

ExampleScene::ExampleScene()
    : Yam3DScene()
    , m_camera(0)
    , m_mesh(0)
    , m_program(0)
{
    // Create cool vertex and fragment shaders.
    QGLShader *vshader = new QGLShader(QGLShader::Vertex);
    char vShaderStr[] =
       "uniform mat4 matModelView;                                                   \n"
       "uniform mat4 matModelViewProj;                                               \n"
       "uniform mat4 matModelViewInverseTranspose;                                   \n"
       "attribute vec4 a_position;                                                   \n"
       "attribute vec3 a_normal;                                                     \n"
       "varying vec3 vNormalES;                                                      \n"
       "varying vec3 vViewVec;                                                       \n"
       "void main()                                                                  \n"
       "{                                                                            \n"
       "   gl_Position = matModelViewProj * a_position;                              \n"
       "   vNormalES   = vec3(matModelViewInverseTranspose * vec4(a_normal, 0.0));   \n"
       "   vViewVec    = -vec3(matModelView * a_position);                           \n"
       "}                                                                            \n";
    vshader->compileSourceCode(vShaderStr);

    QGLShader *fshader = new QGLShader(QGLShader::Fragment);
    char fShaderStr[] =
       "uniform vec4  lightDir;                                                                                      \n"
       "varying vec3 vNormalES;                                                                                      \n"
       "varying vec3 vViewVec;                                                                                       \n"
       "void main()                                                                                                  \n"
       "{                                                                                                            \n"
       "    vec3 normal = normalize(vNormalES);                                                                      \n"
       "    // Soft diffuse                                                                                          \n"
       "    float diffuse = 0.2 + 0.8 * dot(lightDir.xyz, normal);                                                   \n"
       "    // Standard specular                                                                                     \n"
       "    float specular = pow(clamp(dot(reflect(-normalize(vViewVec), normal), lightDir.xyz),0.0, 1.0), 12.0);    \n"
       "                                                                                                             \n"
       "    gl_FragColor = vec4(0.5,0.5,0.5,1.0) * diffuse + vec4(1.0,1.0,1.0,1.0) * specular;                       \n"
       "}                                                                                                            \n";
    fshader->compileSourceCode(fShaderStr);

    assert( m_program == 0 );
    m_program = new QGLShaderProgram();
    m_program->addShader(vshader);
    m_program->addShader(fshader);
    m_program->link();
    m_program->bind();

    // Create camera for our scene.
    assert( m_camera == 0 );
    m_camera = new graphics::Camera();

    m_pass.setCamera(m_camera);
    m_pass.setShaderProgram(m_program);

    graphics::ShaderUniforms* uniforms = new graphics::ShaderUniforms();
    m_pass.setShaderUniforms(uniforms);
}

ExampleScene::~ExampleScene()
{
}

void ExampleScene::resize(int width, int height)
{
    m_camera->setPerspective(60.0f, float(width)/float(height), 1.0f, 1000.0f);
    glViewport( 0,0, width, height);
}

void ExampleScene::update(float deltaTime)
{
    if( m_mesh != 0 )
    {
        m_mesh->setTranslation( QVector3D(0,0,0) );
        m_mesh->setOrientation( m_mesh->getOrientation()
            * (QQuaternion::fromAxisAndAngle(1,0,0,10*deltaTime)
            * QQuaternion::fromAxisAndAngle(0,1,0,13*deltaTime)
            * QQuaternion::fromAxisAndAngle(0,0,1,17*deltaTime)) );
    }

    // Light dir is in world space, convert it to camera space
    QVector4D lightDir =  m_camera->getView().inverted() * QVector4D(0.0f,1.0f,1.0f,0.0f);
    m_pass.getShaderUniforms()->setUniformValue("lightDir", lightDir.normalized() );
}

void ExampleScene::render() const
{
    if( m_mesh != 0 )
    {
        render::Renderer renderer;
        renderer.applyPass(&m_pass);
        renderer.render(m_mesh);
    }
}

void ExampleScene::setWorkingObject(const core::string& fileName)
{
    float maxSize(0.0f);
    m_mesh = graphics::STLLoader::load( fileName, &maxSize );
    m_camera->setTranslation( QVector3D(0,0,2.0f*maxSize) );
    m_camera->setPerspective(m_camera->getAngle(), m_camera->getAspectRatio(), 0.5f*maxSize, 3.5f*maxSize);
}



